package com.xiaoshuidi.cloud.module.finance.service.invoice.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiaoshuidi.cloud.framework.common.core.KeyValue;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.module.finance.controller.admin.invoice.vo.*;
import com.xiaoshuidi.cloud.module.finance.convert.finance.InvoiceConvert;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.invoice.FinanceInvoiceApartmentDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.invoice.FinanceInvoiceConfigDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.invoice.FinanceInvoiceTaxRateDO;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.invoice.FinanceInvoiceApartmentMapper;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.invoice.FinanceInvoiceConfigMapper;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.invoice.FinanceInvoiceTaxRateMapper;
import com.xiaoshuidi.cloud.module.finance.service.invoice.FinanceInvoiceConfigService;
import com.xiaoshuidi.cloud.module.rooms.api.apartment.ApartmentApi;
import com.xiaoshuidi.cloud.module.rooms.api.apartment.dto.ApartmentListDto;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.xiaoshuidi.cloud.module.finance.enums.ErrorCodeConstants.*;

@Service
public class FinanceInvoiceConfigServiceImpl implements FinanceInvoiceConfigService {
    @Resource
    private FinanceInvoiceConfigMapper financeInvoiceConfigMapper;
    @Resource
    private FinanceInvoiceTaxRateMapper financeInvoiceTaxRateMapper;
    @Resource
    private FinanceInvoiceApartmentMapper financeInvoiceApartmentMapper;
    @Resource
    private ApartmentApi apartmentApi;
    @Override
    public Integer save(FinanceInvoiceConfigCreateReqVO reqVO) {
        FinanceInvoiceConfigDO entity = financeInvoiceConfigMapper.selectOne("company_taxpayer_id", reqVO.getCompanyTaxpayerId());
        if (entity != null) {
            throw new ServiceException(FINANCE_INVOICE_CONFIG_EXISTS);
        }
        entity = InvoiceConvert.INSTANCE.convert(reqVO);
        entity.disable(entity::setEnable,
                entity::setPersonReversalApproval,
                entity::setPersonApplyApproval,
                entity::setCompanyReversalApproval,
                entity::setCompanyApplyApproval);

        return financeInvoiceConfigMapper.insert(entity);
    }

    @Override
    public void updateSwitch(FinanceInvoiceConfigSwitchReqVO reqVO) {
        validateInvoiceConfig(reqVO.getId());
        FinanceInvoiceConfigDO update = InvoiceConvert.INSTANCE.convert(reqVO);
        financeInvoiceConfigMapper.updateById(update);
    }

    @Override
    public void update(FinanceInvoiceConfigUpdateReqVO reqVO) {
        validateInvoiceConfig(reqVO.getId());
        FinanceInvoiceConfigDO update = InvoiceConvert.INSTANCE.convert(reqVO);
        update.setId(reqVO.getId());

        financeInvoiceConfigMapper.updateById(update);
    }

    @Override
    public FinanceInvoiceConfigDO getById(Integer id) {
        return validateInvoiceConfig(id);
    }

    @Override
    public void updateTaxRate(FinanceInvoiceFeeTaxReqVO reqVO) {
        validateInvoiceConfig(reqVO.getId());
        financeInvoiceTaxRateMapper.delete(new QueryWrapper<FinanceInvoiceTaxRateDO>()
                .eq("invoice_config_id", reqVO.getId()));
        List<FinanceInvoiceTaxRateDO> l = InvoiceConvert.INSTANCE.convertToList(reqVO.getTaxes());
        l.forEach(t -> t.setInvoiceConfigId(reqVO.getId()));
        financeInvoiceTaxRateMapper.insertBatch(l);
    }

    @Override
    public void updateApartment(FinanceInvoiceConfigApartmentReqVO reqVO) {
        validateInvoiceConfig(reqVO.getId());
        if (CollectionUtils.isEmpty(reqVO.getApartmentIds())) {
            financeInvoiceApartmentMapper.delete(new QueryWrapper<FinanceInvoiceApartmentDO>()
                    .eq("invoice_config_id", reqVO.getId()));
            return;
        }
        List<FinanceInvoiceApartmentDO> la = financeInvoiceApartmentMapper.selectList(new QueryWrapper<FinanceInvoiceApartmentDO>()
                .ne("invoice_config_id", reqVO.getId())
                .in("apartment_id", reqVO.getApartmentIds())
        );
        if (!la.isEmpty()) {
            throw new ServiceException(FINANCE_INVOICE_CONFIG_APARTMENT.getCode(), la.get(0).getApartmentName() + "已关联税号");
        }

        financeInvoiceApartmentMapper.delete(new QueryWrapper<FinanceInvoiceApartmentDO>()
                .eq("invoice_config_id", reqVO.getId()));
        CommonResult<List<ApartmentListDto>> apartments = apartmentApi.listByIds(reqVO.getApartmentIds());
        List<ApartmentListDto> list = apartments.getCheckedData();
        List<FinanceInvoiceApartmentDO> l = list.stream().map(a -> FinanceInvoiceApartmentDO.builder()
                .apartmentId(a.getId())
                .invoiceConfigId(reqVO.getId())
                .apartmentName(a.getName())
                .address(apartmentAddress(a::getProvince, a::getCity, a::getDistrict, a::getStreet, a::getAddress))
                .build()).collect(Collectors.toList());
        financeInvoiceApartmentMapper.insertBatch(l);
    }

    @Override
    public List<FinanceInvoiceTaxRateDO> getFeeTax(Integer id) {
        return financeInvoiceTaxRateMapper.selectList("invoice_config_id", id);
    }

    @Override
    public List<FinanceInvoiceApartmentDO> getApartment(Integer id) {
        return financeInvoiceApartmentMapper.selectList("invoice_config_id", id);
    }

    @Override
    public PageResult<FinanceInvoiceConfigDO> getPage(FinanceInvoiceConfigPageReqVO reqVO) {
        QueryWrapper<FinanceInvoiceConfigDO> qw = new QueryWrapper<>();
        if (StringUtils.hasText(reqVO.getKeyword())) {
            qw.like("company_name", reqVO.getKeyword())
                    .or()
                    .like("drawer", reqVO.getKeyword())
                    .or()
                    .like("payee", reqVO.getKeyword())
                    .or()
                    .like("reviewer", reqVO.getKeyword());
        }
        return financeInvoiceConfigMapper.selectPage(reqVO, qw);
    }

    @Override
    public List<FinanceInvoiceConfigDO> getAll() {
        return financeInvoiceConfigMapper.selectList();
    }

    @Override
    public FinanceInvoiceConfigDO getByApartmentId(Long apartmentId) {
        return financeInvoiceConfigMapper.selectByApartmentId(apartmentId);
    }

    @Override
    public Map<Long, List<Long>> getFeeTaxMap(Collection<Long> apartmentIds) {
        List<KeyValue<Long, Long>> l = financeInvoiceTaxRateMapper.selectByApartmentId(apartmentIds);
        return l.stream().collect(Collectors.groupingBy(KeyValue::getKey, Collectors.mapping(KeyValue::getValue, Collectors.toList())));
    }

    private String apartmentAddress(Supplier<String> ...field) {
        return Stream.of(field)
                .map(s -> StringUtils.hasText(s.get()) ? s.get() : "")
                .collect(Collectors.joining());
    }

    private FinanceInvoiceConfigDO validateInvoiceConfig(Integer id) {
        FinanceInvoiceConfigDO entity = financeInvoiceConfigMapper.selectById(id);
        if (entity == null) {
            throw new ServiceException(FINANCE_INVOICE_CONFIG_NOT_EXISTS);
        }
        return entity;
    }
}
